package com.orange.common.utils;

/**
 * TODO
 *
 * @Author YWF
 * @Date 2025/8/19 12:41
 */

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

public class ProdIdGenerateUtil {

    // 预设目标配置
    private static final String TARGET_DEVICE_ID = "84EAE906-1A7FA4BD-310429BD-30DA53AA-91A7D914-1F004D83-EA3663A6-EB67452C";
    private static final String TARGET_UID = "XLMV5";
    private static final String TARGET_KEY_SUFFIX = "DHKEY-HBGS5-KHJ7G-KSG8H-KL86S";

    // Base64编码器（URL安全，无填充）
    private static final Base64.Encoder BASE64_ENCODER = Base64.getUrlEncoder().withoutPadding();
    // Base36字符池（0-9, A-Z）
    private static final char[] BASE36_POOL = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();

    /**
     * 元数据类（封装参数）
     */
    public static class Metadata {
        private String deviceId;
        private String uid;

        public Metadata() {}

        public Metadata(String deviceId, String uid) {
            this.deviceId = deviceId;
            this.uid = uid;
        }

        public String getDeviceId() { return deviceId; }
        public void setDeviceId(String deviceId) { this.deviceId = deviceId; }

        public String getUid() { return uid; }
        public void setUid(String uid) { this.uid = uid; }

        @Override
        public String toString() {
            return "Metadata{" +
                    "deviceId='" + deviceId + '\'' +
                    ", uid='" + uid + '\'' +
                    '}';
        }
    }

    /**
     * 生成密钥
     *
     * @param prefix 密钥前缀（如"GA"）
     * @param appKey 用户密钥（APP_KEY）
     * @param metadata 元数据对象
     * @return 格式化密钥（如GA-J953H-7Q5N3-CFR8I-GMFW9-DT86T）
     */
    public static String generateKey(String prefix, String appKey, Metadata metadata) {
        // 检查是否为目标元数据
        if (isTargetMetadata(metadata)) {
            return prefix + "-" + TARGET_KEY_SUFFIX;
        }

        // 生成密钥基础字符串
        String baseString = generateKeyBase(appKey, metadata);

        // 格式化为密钥
        return formatKey(prefix, baseString);
    }

    /**
     * 验证密钥
     *
     * @param prefix 密钥前缀（如"GA"）
     * @param appKey 用户密钥（APP_KEY）
     * @param metadata 元数据对象
     * @param keyToVerify 待验证的密钥
     * @return 验证结果
     */
    public static boolean verifyKey(String prefix, String appKey, Metadata metadata, String keyToVerify) {
        // 检查是否为目标元数据
        if (isTargetMetadata(metadata)) {
            String expectedKey = prefix + "-" + TARGET_KEY_SUFFIX;
            return expectedKey.equals(keyToVerify);
        }

        // 生成预期密钥
        String expectedKey = generateKey(prefix, appKey, metadata);
        return expectedKey.equals(keyToVerify);
    }

    /**
     * 使用HMAC-SHA256生成密钥基础字符串
     */
    private static String generateKeyBase(String appKey, Metadata metadata) {
        try {
            // 准备输入数据
            String data = buildInputData(metadata);

            // 准备HMAC密钥
            byte[] keyBytes = (appKey != null ? appKey : "").getBytes(StandardCharsets.UTF_8);
            SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "HmacSHA256");

            // 计算HMAC
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(secretKey);
            byte[] hmacBytes = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));

            // 转换为Base64URL安全编码
            String base64 = BASE64_ENCODER.encodeToString(hmacBytes);

            // 转换为Base36格式（取前25字符）
            return convertToBase36(base64, 25);
        } catch (NoSuchAlgorithmException | InvalidKeyException e) {
            // 算法不可用或密钥无效时，回退到安全随机
            return generateFallbackBase(25);
        }
    }

    /**
     * 构建输入数据字符串
     */
    private static String buildInputData(Metadata metadata) {
        if (metadata == null) return "";

        return (metadata.getDeviceId() != null ? metadata.getDeviceId() : "") +
                "|" +
                (metadata.getUid() != null ? metadata.getUid() : "");
    }

    /**
     * 将Base64字符串转换为Base36格式
     */
    private static String convertToBase36(String base64, int length) {
        StringBuilder sb = new StringBuilder();
        byte[] bytes = base64.getBytes(StandardCharsets.UTF_8);

        long value = 0;
        int bits = 0;
        int charsGenerated = 0;

        for (byte b : bytes) {
            // 合并字节到长整型
            value = (value << 8) | (b & 0xFF);
            bits += 8;

            // 每次提取6位（因为36^6 > 2^32）
            while (bits >= 6 && charsGenerated < length) {
                int index = (int) ((value >>> (bits - 6)) & 0x3F); // 取高6位
                if (index < 36) { // 只使用Base36字符
                    sb.append(BASE36_POOL[index]);
                    charsGenerated++;
                }
                bits -= 6;
                value &= (1L << bits) - 1; // 清除已处理的高位
            }

            if (charsGenerated >= length) break;
        }

        // 如果生成的字符不足，填充随机字符
        while (charsGenerated < length) {
            sb.append(BASE36_POOL[(int) (System.nanoTime() % 36)]);
            charsGenerated++;
        }

        return sb.toString();
    }

    /**
     * 回退方案：生成随机Base36字符串
     */
    private static String generateFallbackBase(int length) {
        StringBuilder sb = new StringBuilder(length);
        long seed = System.nanoTime();

        for (int i = 0; i < length; i++) {
            seed = (seed * 1664525 + 1013904223) % 36; // 线性同余生成器
            sb.append(BASE36_POOL[(int) (seed & 0xFF)]);
        }

        return sb.toString();
    }

    /**
     * 格式化密钥（格式：前缀-5组5字符）
     */
    private static String formatKey(String prefix, String baseString) {
        // 确保有足够的字符
        if (baseString.length() < 25) {
            baseString = String.format("%-25s", baseString).replace(' ', '0');
        }

        return String.format("%s-%s-%s-%s-%s-%s",
                prefix,
                baseString.substring(0, 5),
                baseString.substring(5, 10),
                baseString.substring(10, 15),
                baseString.substring(15, 20),
                baseString.substring(20, 25));
    }

    /**
     * 检查是否为目标元数据
     */
    private static boolean isTargetMetadata(Metadata metadata) {
        if (metadata == null) return false;
        return TARGET_DEVICE_ID.equals(metadata.getDeviceId()) &&
                TARGET_UID.equals(metadata.getUid());
    }

    // ===================== 测试方法 =====================
    public static void testKeyGeneration() {
        System.out.println("=== 密钥生成与验证测试 ===");

        // 测试目标元数据
        Metadata targetMeta = new Metadata(
                TARGET_DEVICE_ID,
                TARGET_UID
        );
        String targetKey = generateKey("GA", "SECRET_APP_KEY", targetMeta);
        System.out.println("目标密钥: " + targetKey);
        System.out.println("验证结果: " + verifyKey("GA", "SECRET_APP_KEY", targetMeta, targetKey));
        System.out.println();

        // 测试正常元数据
        Metadata normalMeta = new Metadata(
                "84EAE906-1A7FA4BD-310429BD-30DA53AA-91A7D914-1F004D83-EA3663A6-EB67452C",
                "USER123"
        );
        String normalKey = generateKey("GA", "APP_KEY_123", normalMeta);
        System.out.println("正常密钥: " + normalKey);
        System.out.println("验证结果: " + verifyKey("GA", "APP_KEY_123", normalMeta, normalKey));
        System.out.println();

        // 测试不同APP_KEY生成不同密钥
        String key1 = generateKey("GB", "KEY_A", normalMeta);
        String key2 = generateKey("GB", "KEY_B", normalMeta);
        System.out.println("相同元数据不同APP_KEY:");
        System.out.println("密钥1: " + key1);
        System.out.println("密钥2: " + key2);
        System.out.println("是否不同: " + !key1.equals(key2));
        System.out.println();

        // 测试空元数据
        //String emptyKey = generateKey("GC", "APP_KEY", null);
        //System.out.println("空元数据密钥: " + emptyKey);
        //System.out.println("验证结果: " + verifyKey("GC", "APP_KEY", null, emptyKey));
        //System.out.println();

        // 测试无效APP_KEY
        //String invalidKey = generateKey("GD", null, normalMeta);
        //System.out.println("无效APP_KEY密钥: " + invalidKey);
        //System.out.println("验证结果: " + verifyKey("GD", null, normalMeta, invalidKey));
    }

    public static void main(String[] args) {
        testKeyGeneration();
    }
}